﻿using GameToolkit.ContentProvider;
using UnityEditor;
using UnityEngine;

namespace GameToolkit.Editor
{
    [CustomPropertyDrawer(typeof(TextReference))]
    [CustomPropertyDrawer(typeof(DeclareTextReferenceAttribute))]
    public class TextReferenceDrawer : PropertyDrawer
    {
        const float LINE_HEIGHT = 18f;

        public override float GetPropertyHeight(SerializedProperty property, GUIContent label)
        {
            var att = attribute as DeclareTextReferenceAttribute;
            if(att != null && att.TextAreaHeight > LINE_HEIGHT)
            {
                var f = Mathf.CeilToInt(att.TextAreaHeight / LINE_HEIGHT);
                return f * LINE_HEIGHT;
            }
            else
            {
                return LINE_HEIGHT;
            }
        }

        int CalculateTextID(SerializedProperty property, SerializedProperty p_id)
        {
            int id = p_id.intValue;
            var att = attribute as DeclareTextReferenceAttribute;
            string declare = att == null || string.IsNullOrEmpty(att.Declaration) ? property.name : att.Declaration;
            string guid;
            var obj = property.serializedObject.targetObject;
            if(obj != null)
            {
                var prefType = PrefabUtility.GetPrefabAssetType(obj);
            }
            long localid;
            if (obj == null)
            {
                guid = "-";
            }
            else if (att == null)
            {
                if (!AssetDatabase.TryGetGUIDAndLocalFileIdentifier(obj, out guid, out localid))
                    guid = $"tp::{obj.GetType().FullName}";
            }
            else if (!att.PerAssetDeclare || !AssetDatabase.TryGetGUIDAndLocalFileIdentifier(obj, out guid, out localid))
            {
                guid = string.IsNullOrEmpty(att.Declaration) ? $"tp::{obj.GetType().FullName}" : "-";
            }
            else
            {
                guid = "-";
            }
            id = TextReference.GetDeclareID(null, declare, guid);
            return id;
        }

        public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)
        {
            var att = attribute as DeclareTextReferenceAttribute;
            var multi = property.hasMultipleDifferentValues;
            if (!multi && att != null && att.PerAssetDeclare && property.serializedObject.isEditingMultipleObjects)
                multi = true;
            var copy = property.Copy();
            var depth = copy.depth + 1;
            var prefix = EditorGUI.BeginProperty(position, label, property);
            SerializedProperty p_id = null, p_txt = null;
            if(copy.NextVisible(true) && copy.depth == depth)
            {
                p_id = copy.Copy();
                prefix.tooltip = multi ? "Is editing multi values." : string.Format("ID: {0} (0x{1})", p_id.intValue, p_id.intValue.ToString("X"));
                if (copy.NextVisible(false) && copy.depth == depth)
                    p_txt = copy.Copy();
            }

            var lv = EditorGUI.indentLevel;
            var row = new Rect(position.x, position.y, position.width, LINE_HEIGHT);
            row = EditorGUI.PrefixLabel(row, prefix);
            EditorGUI.indentLevel = 0;

            if (p_txt == null || p_id == null)
            {
                EditorGUI.LabelField(row, "The property type is not TextReference.");
            }
            else
            {
                string txt = p_txt.stringValue;
                if(att != null && att.TextAreaHeight > LINE_HEIGHT)
                {
                    row = new Rect(position.x, position.y + LINE_HEIGHT, position.width, position.height - LINE_HEIGHT);
                    txt = EditorGUI.TextArea(row, txt);
                }
                else
                {
                    txt = EditorGUI.TextField(row, txt);
                }
                var id = CalculateTextID(property, p_id);
                if (id != p_id.intValue || txt != p_txt.stringValue)
                {
                    p_id.intValue = id;
                    p_txt.stringValue = txt;
                    GUI.changed = true;
                }
            }

            EditorGUI.indentLevel = lv;
            EditorGUI.EndProperty();
        }
    }
}
